package com.woohua.thread.limite;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

/***
 * @title LimitRule
 * @description:限流规则，可以设置匹配url的正则表达式和最大流量值，同时获取该规则的流量通信证和释放流量通行证
 * @author woo hua
 * @version 1.0.0
 * @create 2023/3/14 8:56
 **/
public class LimitRule {

    /**
     * 信号量
     */
    private final Semaphore sema;

    /**
     * 请求URL匹配规则
     */
    private final String pattern;

    /**
     * 最大并发数
     */
    private final int maxConcurrent;


    public LimitRule(String pattern, int maxConcurrent) {
        this.sema = new Semaphore(maxConcurrent);
        this.pattern = pattern;
        this.maxConcurrent = maxConcurrent;
    }

    /**
     * 获取通行证。这里加同步是为了打印可用通行证数量时，看起来逐个减少或逐个增加，无此打印需求可不加synchronized关键字
     *
     * @param urlPath 请求url
     * @return 0-获取成功，1-没有获取到通行证，2-不需要获取通行证
     */
    public synchronized AcquireResult tryAcquire(String urlPath) {
        AcquireResult acquireResult = new AcquireResult();
        acquireResult.setAvailablePermits(this.sema.availablePermits());

        if (Pattern.matches(pattern, urlPath)) {
            try {
                boolean acquire = this.sema.tryAcquire(50, TimeUnit.MICROSECONDS);
                if (acquire) {
                    acquireResult.setResult(AcquireResult.ACQUIRE_SUCCESS);
                } else {
                    acquireResult.setResult(AcquireResult.ACQUIRE_FAILED);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            acquireResult.setResult(AcquireResult.ACQUIRE_NO_NEED);
        }
        return acquireResult;
    }

    /**
     * 释放通行证。这里加同步是为了打印可用通行证数量时，看起来逐个减少或逐个增加，无此打印需求可不加synchronized关键字
     */
    public void release() {
        this.sema.release();
        print(null);
    }

    /**
     * 得到最大并发数
     *
     * @return
     */
    public int getMaxConcurrent() {
        return this.maxConcurrent;
    }

    public String getPattern() {
        return this.pattern;
    }

    /**
     * 打印日志
     *
     * @param urlPath
     */
    private void print(String urlPath) {
        StringBuffer buffer = new StringBuffer();
        buffer.append("Pattern: ").append(pattern).append(", ");
        if (null != urlPath) {
            buffer.append("Pattern: ").append(urlPath).append(", ");
        }
        buffer.append("Available Permits:").append(this.sema.availablePermits());
        System.out.println(buffer);
    }
}
